using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using TesteIATcc.Comuns;

namespace TesteIATcc.Entidades
{
    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class Jogador : Microsoft.Xna.Framework.GameComponent
    {
        #region atributos
        private Sprite spriteJogador;
        private Sprite cockpitJogador;
        private Sprite escudoJogador;
        private List<Sprite> tiroJogador;

        private AjudanteJogador ajudante01;

        private float timerDoTiro = 0f;
        private float intervaloDoTiro = 0.08f;

        private float timerDoMovimento = 0f;
        private float intervaloDoMovimento = 0.12f;

        private float timerDoRespawn = 0f;
        private float intervaloDoRespawn = 3f;

        private int scoreJogador = 0;
        #endregion
        #region getteres e setters
        public Sprite SpriteJogador
        {
            get { return spriteJogador; }
            set { spriteJogador = value; }
        }
        public List<Sprite> TiroJogador
        {
            get { return tiroJogador; }
            set { tiroJogador = value; }
        }
        public int ScoreJogador
        {
            get { return scoreJogador; }
            set { scoreJogador = value; }
        }
        public AjudanteJogador Ajudante01
        {
            get { return ajudante01; }
            set { ajudante01 = value; }
        }
        #endregion

        //construtor
        public Jogador(TesteIA game)
            : base(game)
        {
            this.spriteJogador = new Sprite(game, "sprites\\nave01", new Vector2(64f, 64f), 0);
            base.Game.Components.Add(this.spriteJogador);

            this.cockpitJogador = new Sprite(game, "sprites\\cockpit", new Vector2(800f, 80f), 0);
            base.Game.Components.Add(this.cockpitJogador);

            this.escudoJogador = new Sprite(game, "sprites\\escudo", new Vector2(800f, 80f), 0);
            base.Game.Components.Add(this.escudoJogador);

            this.tiroJogador = new List<Sprite>();

            //inicializa tres tiros
            for (int i = 0; i <= 2; i++)
            {
                this.tiroJogador.Add(new Sprite(game, "sprites\\tirojogador", new Vector2(8f, 8f), 0));
                this.tiroJogador[i].Visible = false;
                base.Game.Components.Add(tiroJogador[i]);
            }

            this.ajudante01 = new AjudanteJogador(game, "sprites\\ajudantejogador", "sprites\\tiroajudante", this);
            base.Game.Components.Add(this.ajudante01);
        }

        #region metodos da interface
        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            this.spriteJogador.PosicaoSprite = new Point(100, 100);
            this.cockpitJogador.PosicaoSprite = new Point(0, base.Game.GraphicsDevice.Viewport.Height - (int)this.cockpitJogador.TamanhoSprite.Y);
            this.escudoJogador.PosicaoSprite = this.cockpitJogador.PosicaoSprite;
            this.ReposicionaTiroInvisivel();
            base.Initialize();
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            #region input do teclado
            //atualiza o input do teclado, sem deixar o jogador sair da tela e passar por cima do cockpit
            //atualiza tambem a posicao do tiro perto da nave.
            timerDoMovimento += (float)gameTime.ElapsedGameTime.TotalMilliseconds;

            if (!this.spriteJogador.Visible)
            {
                this.Morrer((float)gameTime.ElapsedGameTime.TotalSeconds);
            }

            if (timerDoMovimento > intervaloDoMovimento)
            {
                timerDoMovimento = 0f;

                KeyboardState kbd = Keyboard.GetState();
                //move o player para cima
                if ((kbd.IsKeyDown(Keys.Up)) && (this.spriteJogador.PosicaoSprite.Y > 0))
                {
                    this.spriteJogador.PosicaoSprite = new Point(this.spriteJogador.PosicaoSprite.X, this.spriteJogador.PosicaoSprite.Y - 4);
                    this.ReposicionaTiroInvisivel();
                };
                //move o player para baixo
                if ((kbd.IsKeyDown(Keys.Down)) && (this.spriteJogador.PosicaoSprite.Y < (base.Game.GraphicsDevice.Viewport.Height - (this.cockpitJogador.TamanhoSprite.Y * 2))))
                {
                    this.spriteJogador.PosicaoSprite = new Point(this.spriteJogador.PosicaoSprite.X, this.spriteJogador.PosicaoSprite.Y + 4);
                    this.ReposicionaTiroInvisivel();
                };
                //move o player para esquerda
                if ((kbd.IsKeyDown(Keys.Left)) && (this.spriteJogador.PosicaoSprite.X > 0))
                {
                    this.spriteJogador.PosicaoSprite = new Point(this.spriteJogador.PosicaoSprite.X - 4, this.spriteJogador.PosicaoSprite.Y);
                    this.ReposicionaTiroInvisivel();
                };
                //move o player para direita
                if ((kbd.IsKeyDown(Keys.Right)) && (this.spriteJogador.PosicaoSprite.X < (base.Game.GraphicsDevice.Viewport.Width - (this.spriteJogador.TamanhoSprite.X ))))
                {
                    this.spriteJogador.PosicaoSprite = new Point(this.spriteJogador.PosicaoSprite.X + 4, this.spriteJogador.PosicaoSprite.Y);
                    this.ReposicionaTiroInvisivel();
                };

                //controla qtde de disparos
                if (kbd.IsKeyDown(Keys.Space))
                {
                    this.timerDoTiro += (float)gameTime.ElapsedGameTime.TotalSeconds;

                    //verifica se o jogador pode disparar novamente
                    if (this.timerDoTiro >= this.intervaloDoTiro)
                    {
                        //zera o timer
                        this.timerDoTiro = 0f;

                        for (int i = 0; i <= 2; i++)
                        {
                            //se o tiro nao estiver visivel e a barra de espaco estiver apertada, faz ele ficar visivel pra ir ate o fim da tela
                            if (!this.tiroJogador[i].Visible)
                            {
                                this.tiroJogador[i].Visible = true;
                                break;
                            }

                            //tiro saiu da tela, deixar ele invisivel e reposicionar perto do jogador
                            if (this.tiroJogador[i].PosicaoSprite.X > base.Game.GraphicsDevice.Viewport.Width)
                            {
                                this.tiroJogador[i].Visible = false;
                                this.ReposicionaTiroInvisivel();
                            }
                        }
                    }
                }
            }
            
            //controla a trajetoria do tiro
            //tiro estiver visivel, vai andando com ele ate o fim da tela
            for (int i = 0; i <= 2; i++)
            {
                if (this.tiroJogador[i].Visible)
                {
                    this.tiroJogador[i].PosicaoSprite = new Point(this.tiroJogador[i].PosicaoSprite.X + 15, this.tiroJogador[i].PosicaoSprite.Y);
                }
            }

            #endregion

            #region eventos em tela
            #endregion

            base.Update(gameTime);
        }
        #endregion

        #region metodos proprios da classe
        /// <summary>
        /// reposiciona o tiro do jogador perto da nave
        /// </summary>
        public void ReposicionaTiroInvisivel()
        {
            for (int i = 0; i <= 2; i++)
            {
                //se o tiro nao estiver visivel, quer dizer que ele ainda nao foi disparado. nesse caso,
                //reposiciona ele
                if (!this.tiroJogador[i].Visible)
                {
                    this.tiroJogador[i].PosicaoSprite = new Point(this.spriteJogador.PosicaoSprite.X + ((int)this.spriteJogador.TamanhoSprite.X / 2),
                        this.spriteJogador.PosicaoSprite.Y + ((int)this.spriteJogador.TamanhoSprite.Y / 2));
                }
            }
        }

        public void Morrer(float totalSeconds)
        {
            this.timerDoRespawn += totalSeconds;
            this.spriteJogador.PosicaoSprite = new Point(100, 100);

            if (this.timerDoRespawn > this.intervaloDoRespawn)
            {
                this.spriteJogador.Visible = true;
                this.timerDoRespawn = 0f;
            }
        }
        #endregion
    }
}